package com.feng.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.feng.domain.ResponseResult;
import com.feng.domain.dto.GetUserListDto;
import com.feng.domain.dto.SystemUpdateUserDto;
import com.feng.domain.dto.SystemUserAddDto;
import com.feng.domain.entity.LoginUser;
import com.feng.domain.entity.Role;
import com.feng.domain.entity.UserRole;
import com.feng.domain.vo.*;
import com.feng.enums.AppHttpCodeEnum;
import com.feng.exception.SystemException;
import com.feng.mapper.UserMapper;
import com.feng.domain.entity.User;
import com.feng.mapper.UserRoleMapper;
import com.feng.service.RoleService;
import com.feng.service.UserRoleService;
import com.feng.service.UserService;
import com.feng.utils.BeanCopyUtil;
import com.feng.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 用户表(User)表服务实现类
 *
 * @author makejava
 * @since 2023-04-15 16:29:46
 */
@Service()
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RoleService roleService;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Override
    public ResponseResult userInfo() {
        Long userId = SecurityUtils.getUserId();
        User user = getById(userId);
        UserInfoVo userInfoVo = BeanCopyUtil.articleVo(user, UserInfoVo.class);
        return ResponseResult.okResult(userInfoVo);
    }

    @Override
    public ResponseResult updateUserInfo(User user) {
        if(updateNikeNameExist(user.getNickName(), user.getId())){
            throw new SystemException(AppHttpCodeEnum.NICKNAME_EXIST);
        }
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper();
        updateWrapper.set(User::getAvatar, user.getAvatar())
                        .set(User::getNickName, user.getNickName())
                                .set(User::getSex, user.getSex())
                                        .eq(User::getId,user.getId());
        update(updateWrapper);
        return ResponseResult.okResult();
    }

    private boolean updateNikeNameExist(String nickName, Long userId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper();
        wrapper.eq(User::getNickName, nickName)
                .ne(User::getId, userId);
        long count = count(wrapper);
        return count > 0;
    }

    @Transactional
    @Override
    public ResponseResult register(User user) {
        if(!StringUtils.hasText(user.getUserName())){
            throw new SystemException(AppHttpCodeEnum.USERNAME_NOT_NULL);
        }
        if(!StringUtils.hasText(user.getNickName())){
            throw new SystemException(AppHttpCodeEnum.NICKNAME_NOT_NULL);
        }
        if(!StringUtils.hasText(user.getEmail())){
            throw new SystemException(AppHttpCodeEnum.EMAIL_NOT_NULL);
        }
        if(!StringUtils.hasText(user.getPassword())){
            throw new SystemException(AppHttpCodeEnum.PASSWORD_NOT_NULL);
        }
        if(userNameExist(user.getUserName())){
            throw new SystemException(AppHttpCodeEnum.USERNAME_EXIST);
        }
        if(nikeNameExist(user.getNickName())){
            throw new SystemException(AppHttpCodeEnum.NICKNAME_EXIST);
        }
        if(emailExist(user.getEmail())){
            throw new SystemException(AppHttpCodeEnum.EMAIL_EXIST);
        }

        String encodePassWord = passwordEncoder.encode(user.getPassword());

        user.setPassword(encodePassWord);

        save(user);

        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult getUserList(Integer pageNum, Integer pageSize, GetUserListDto listDto) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasText(listDto.getUserName()), User::getUserName, listDto.getUserName());
        wrapper.eq(StringUtils.hasText(listDto.getPhonenumber()), User::getPhonenumber, listDto.getPhonenumber());
        wrapper.eq(StringUtils.hasText(listDto.getStatus()), User::getStatus, listDto.getStatus());
        Page<User> page = new Page<>();
        page.setCurrent(pageNum);
        page.setSize(pageSize);
        page(page, wrapper);
        List<GetUserListVo> getUserListVos = BeanCopyUtil.articleListVo(page.getRecords(), GetUserListVo.class);
        return ResponseResult.okResult(new ArticleListPageVo(getUserListVos, page.getTotal()));
    }

    @Transactional
    @Override
    public ResponseResult addUser(SystemUserAddDto addDto) {
        if(!StringUtils.hasText(addDto.getUserName())){
            throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME);
        }
        if(!StringUtils.hasText(addDto.getNickName())){
            throw new SystemException(AppHttpCodeEnum.NICKNAME_NOT_NULL);
        }
        if(!StringUtils.hasText(addDto.getEmail())){
            throw new SystemException(AppHttpCodeEnum.EMAIL_NOT_NULL);
        }
        if(!StringUtils.hasText(addDto.getPassword())){
            throw new SystemException(AppHttpCodeEnum.PASSWORD_NOT_NULL);
        }
        if(!StringUtils.hasText(addDto.getPhonenumber())){
            throw new SystemException(AppHttpCodeEnum.PHONE_NOT_NULL);
        }
        if(userNameExist(addDto.getUserName())){
            throw new SystemException(AppHttpCodeEnum.USERNAME_EXIST);
        }
        if(nikeNameExist(addDto.getNickName())){
            throw new SystemException(AppHttpCodeEnum.NICKNAME_EXIST);
        }
        if(emailExist(addDto.getEmail())){
            throw new SystemException(AppHttpCodeEnum.EMAIL_EXIST);
        }
        if(phoneExist(addDto.getPhonenumber())){
            throw new SystemException(AppHttpCodeEnum.PHONENUMBER_EXIST);
        }
        User user = BeanCopyUtil.articleVo(addDto, User.class);
        String passwordEncode = passwordEncoder.encode(addDto.getPassword());
        user.setPassword(passwordEncode);
        save(user);
        if(!addDto.getRoleIds().isEmpty()){

            List<UserRole> userRoles = addDto.getRoleIds().stream().parallel()
                    .map(roleId -> new UserRole(user.getId(), roleId))
                    .collect(Collectors.toList());
            userRoleService.saveBatch(userRoles);
        }
        return ResponseResult.okResult();
    }

    @Transactional
    @Override
    public ResponseResult delUser(List<Long> ids) {
        getBaseMapper().deleteBatchIds(ids);
        for (Long id: ids) {
            LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserRole::getUserId, id);
            userRoleService.getBaseMapper().delete(wrapper);
        }
        return ResponseResult.okResult();
    }

    @Transactional
    @Override
    public ResponseResult getUser(Long id) {
        User user = getById(id);
        LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserRole::getUserId,id);
        List<UserRole> userRoles =userRoleService.list(wrapper);
        List<Role> roleAll = roleService.list();
        SystemUpdateUserVo systemUpdateUserVo = BeanCopyUtil.articleVo(user, SystemUpdateUserVo.class);
        List<Long> userRoleVo = userRoles.stream().parallel()
                .map(userRole -> userRole.getRoleId())
                .collect(Collectors.toList());
        List<SystemRoleAllVo> systemRoleAllVos = BeanCopyUtil.articleListVo(roleAll, SystemRoleAllVo.class);

        return ResponseResult.okResult(new SystemReturnUserVo(userRoleVo, systemRoleAllVos, systemUpdateUserVo));
    }

    @Transactional
    @Override
    public ResponseResult updateUser(SystemUpdateUserDto userDto) {
        User user = BeanCopyUtil.articleVo(userDto, User.class);
        updateById(user);
        LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserRole::getUserId, userDto.getId());
        userRoleMapper.delete(wrapper);
        if(!userDto.getRoleIds().isEmpty()){
            List<UserRole> userRoles = userDto.getRoleIds().stream().parallel()
                    .map(roleId -> new UserRole(userDto.getId(), roleId))
                    .collect(Collectors.toList());
            userRoleService.saveBatch(userRoles);
        }
        return ResponseResult.okResult();
    }

    private boolean phoneExist(String phonenumber) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper();
        wrapper.eq(User::getPhonenumber, phonenumber);
        long count = count(wrapper);
        return count > 0;
    }

    private boolean emailExist(String email) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper();
        wrapper.eq(User::getEmail, email);
        long count = count(wrapper);
        return count > 0;
    }

    private boolean nikeNameExist(String nickName) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper();
        wrapper.eq(User::getNickName, nickName);
        long count = count(wrapper);
        return count > 0;
    }

    private boolean userNameExist(String userName) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper();
        wrapper.eq(User::getUserName, userName);
        long count = count(wrapper);
        return count > 0;
    }
}

